package com.gitee.wsl.func.transform.sample

import com.gitee.wsl.func.predicate.Predicate
import com.gitee.wsl.func.transform.Transformer


/**
 * Transformer implementation calls the transformer whose predicate returns true,
 * like a switch statement.
 *
 * @param <T> the type of the input to the function.
 * @param <R> the type of the result of the function.
 * @since 3.0
</R></T> */
class SwitchTransformer<T, R> private constructor(
    clone: Boolean,
    val predicates: Array<Predicate<in T>>,
    val transformers: Array<Transformer<in T, out R>>,
    val defaultTransformer: Transformer<in T, out R> = ConstantTransformer.nullTransformer(),
) : Transformer<T, R>{

    /**
     * Transforms the input to result by calling the transformer whose matching
     * predicate returns true.
     *
     * @param input  the input object to transform
     * @return the transformed result
     */
     override fun transform(input: T): R {
        for (i in predicates.indices) {
            if (predicates[i].test(input)) {
                return transformers[i].apply(input)
            }
        }
        return defaultTransformer.apply(input)
    }

    companion object {

        /**
         * Create a new Transformer that calls one of the transformers depending
         * on the predicates.
         *
         *
         * The Map consists of Predicate keys and Transformer values. A transformer
         * is called if its matching predicate returns true. Each predicate is evaluated
         * until one returns true. If no predicates evaluate to true, the default
         * transformer is called. The default transformer is set in the map with a
         * null key. The ordering is that of the iterator() method on the entryset
         * collection of the map.
         *
         * @param <I>  the input type
         * @param <O>  the output type
         * @param map  a map of predicates to transformers
         * @return the `switch` transformer
         * @throws NullPointerException if the map is null
         * @throws NullPointerException if any transformer in the map is null
         * @throws ClassCastException  if the map elements are of the wrong type
        </O></I> */
//        fun <I, O> switchTransformer(
//            map: Map<out Predicate<in I>, out Transformer<in I, out O>>,
//        ): Transformer<I, O> {
//            if (map.isEmpty()) {
//                return ConstantTransformer.nullTransformer<I, O>()
//            }
//            // convert to array like this to guarantee iterator() ordering
//            val defaultTransformer = map.remove(null)
//            val size: Int = map.size
//            if (size == 0) {
//                return (if (defaultTransformer == null) ConstantTransformer.nullTransformer() else defaultTransformer) as Transformer<I, O>
//            }
//            val transformers= kotlin.arrayOfNulls<Transformer>(size)
//            val preds: Array<Predicate<in I?>?> = kotlin.arrayOfNulls<Predicate<*>>(size)
//            var i = 0
//            for (entry in map.entrySet()) {
//                preds[i] = entry.getKey()
//                transformers[i] = entry.getValue()
//                i++
//            }
//            return SwitchTransformer<I?, Any?>(false, preds, transformers, defaultTransformer)
//        }

        /**
         * Factory method that performs validation and copies the parameter arrays.
         *
         * @param <I>  the input type
         * @param <O>  the output type
         * @param predicates  array of predicates, cloned, no nulls
         * @param transformers  matching array of transformers, cloned, no nulls
         * @param defaultTransformer  the transformer to use if no match, null means return null
         * @return the `chained` transformer
         * @throws NullPointerException if either array is null
         * @throws NullPointerException if any element in the arrays is null
         * @throws IllegalArgumentException if the arrays have different sizes
        </O></I> */
//        fun <I, O> switchTransformer(
//            predicates: Array<Predicate<in I?>?>,
//            transformers: Array<Transformer<in I?, out O?>?>,
//            defaultTransformer: Transformer<in I?, out O?>?,
//        ): Transformer<I?, O?>? {
//            FunctorUtils.validate(predicates)
//            FunctorUtils.validate(transformers)
//            require(predicates.size == transformers.size) { "The predicate and transformer arrays must be the same size" }
//            if (predicates.size == 0) {
//                return (if (defaultTransformer == null) ConstantTransformer.< I, O>nullTransformer<I?, O?>() else defaultTransformer) as Transformer<I?, O?>?
//            }
//            return SwitchTransformer<I?, Any?>(predicates, transformers, defaultTransformer)
//        }
    }
}
